#include "Leds.h"

#include "Timer.h"

struct _Leds
{
        Timer    parent_instance;
        uint16_t pin;
        bool     is_blinking;
};

static bool is_inited = false;
static Leds global_leds;

static void
leds_timer_cb(const Leds *self)
{
        static bool flag = false;
        if (flag)
                GPIO_ResetBits(GPIOB, self->pin);
        else
                GPIO_SetBits(GPIOB, self->pin);
        flag = !flag;
}

void
leds_set_byte(Leds *self, const uint8_t byte)
{
        uint16_t pin  = GPIO_Pin_6;
        uint8_t  flag = 0x01;
        for (char i = 0; i < 8; ++i) {
                if (byte & flag)
                        GPIO_ResetBits(GPIOB, pin);
                else
                        GPIO_SetBits(GPIOB, pin);
                flag <<= 1;
                if (i < 3 || i >= 4)
                        pin >>= 1;
                else
                        pin = GPIO_Pin_15;
        }
}

void
leds_set_mode(Leds *self, const LedsMode mode)
{
        switch (mode) {
        case LEDS_MODE_NONE_MODE:
                GPIO_SetBits(GPIOB, GPIO_Pin_12);
                GPIO_SetBits(GPIOB, GPIO_Pin_13);
                GPIO_SetBits(GPIOB, GPIO_Pin_14);
                GPIO_SetBits(GPIOB, GPIO_Pin_15);
                break;
        case LEDS_MODE_FAST_MODE:
                leds_set_byte(self, 0x80);
                break;
        case LEDS_MODE_SLOW_MODE:
                leds_set_byte(self, 0x40);
                break;
        case LEDS_MODE_AUTO_MODE:
                leds_set_byte(self, 0x20);
                break;
        case LEDS_MODE_HAND_MODE:
                leds_set_byte(self, 0x10);
                break;
        case LEDS_MODE_STOP_CHARGE:
                timer_stop(TIMER(self));
                self->is_blinking = false;
                GPIO_SetBits(GPIOB, GPIO_Pin_6);
                GPIO_ResetBits(GPIOB, GPIO_Pin_4);
                break;
        case LEDS_MODE_SYS_ERROR:
                if (!self->is_blinking) {
                        leds_set_byte(self, 0x02);
                        self->pin = GPIO_Pin_5;
                        timer_set_psc_arr(TIMER(self), 7200, 2500);
                        timer_start(TIMER(self));
                        self->is_blinking = true;
                }
                break;
        case LEDS_MODE_FAST_CHARGE:
                timer_stop(TIMER(self));
                self->is_blinking = false;
                GPIO_SetBits(GPIOB, GPIO_Pin_4);
                GPIO_ResetBits(GPIOB, GPIO_Pin_6);
                break;
        case LEDS_MODE_SLOW_CHARGE:
                if (!self->is_blinking) {
                        GPIO_SetBits(GPIOB, GPIO_Pin_4);
                        GPIO_ResetBits(GPIOB, GPIO_Pin_6);
                        self->pin = GPIO_Pin_6;
                        timer_set_psc_arr(TIMER(self), 7200, 10000);
                        timer_start(TIMER(self));
                        self->is_blinking = true;
                }
                break;
        case LEDS_MODE_WAIT_ORDER:
                GPIO_ResetBits(GPIOB, GPIO_Pin_3);
                break;
        case LEDS_MODE_WAIT_FINISH:
                GPIO_SetBits(GPIOB, GPIO_Pin_3);
                break;
        case LEDS_MODE_DISABLE:
                GPIO_SetBits(GPIOB, GPIO_Pin_12);
                GPIO_SetBits(GPIOB, GPIO_Pin_13);
                GPIO_SetBits(GPIOB, GPIO_Pin_14);
                GPIO_SetBits(GPIOB, GPIO_Pin_15);
                timer_stop(TIMER(self));
                self->is_blinking = false;
                GPIO_SetBits(GPIOB, GPIO_Pin_6);
                GPIO_SetBits(GPIOB, GPIO_Pin_4);
                GPIO_SetBits(GPIOB, GPIO_Pin_3);
                GPIO_SetBits(GPIOB, GPIO_Pin_5);
                break;
        }
}

Leds *
leds_new_from_global(void)
{
        if (is_inited)
                return &global_leds;
        timer_init(TIMER(&global_leds),
                   OBJECT_IRQ_HANDLER(leds_timer_cb),
                   7200,
                   1000);

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        // 关闭调试功能，重定义 PB3 PB4 引脚
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
        GPIO_InitTypeDef gpio = {.GPIO_Mode = GPIO_Mode_Out_PP,
                                 .GPIO_Pin  = GPIO_Pin_12 | GPIO_Pin_13 |
                                             GPIO_Pin_14 | GPIO_Pin_15 |
                                             GPIO_Pin_3 | GPIO_Pin_4 |
                                             GPIO_Pin_5 | GPIO_Pin_6,
                                 .GPIO_Speed = GPIO_Speed_50MHz};
        GPIO_Init(GPIOB, &gpio);
        GPIO_SetBits(GPIOB, GPIO_Pin_3);
        GPIO_SetBits(GPIOB, GPIO_Pin_4);
        GPIO_SetBits(GPIOB, GPIO_Pin_5);
        GPIO_SetBits(GPIOB, GPIO_Pin_6);
        GPIO_SetBits(GPIOB, GPIO_Pin_12);
        GPIO_SetBits(GPIOB, GPIO_Pin_13);
        GPIO_SetBits(GPIOB, GPIO_Pin_14);
        GPIO_SetBits(GPIOB, GPIO_Pin_15);
        global_leds.pin         = GPIO_Pin_6;
        global_leds.is_blinking = false;
        //
        is_inited = true;
        return &global_leds;
}
